package com.cypher.encryptionanddecryption.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;

import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.alibaba.fastjson.JSONObject;
import com.cypher.encryptionanddecryption.R;
import com.cypher.encryptionanddecryption.bean.CommunicationBean;
import com.cypher.encryptionanddecryption.bluetooth.BluetoothGattManager;
import com.cypher.encryptionanddecryption.bluetooth.BluetoothManagerSingleton;
import com.cypher.encryptionanddecryption.fragment.protocol.kunlun.ErrCodeFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.AbstractProtocolFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.kunlun.FlowCoefficientFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.kunlun.KunLunTimeQuantumFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.kunlun.MeterNumberFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.kunlun.ParamFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.kunlun.ReadonlyFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.kunlun.WriteStateFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.AbnormallyHighFlowParamsFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.ClockFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.CollectionServiceParamFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.MeterStateFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.SecretKeyParamFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.SimpleEditFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.SimpleSpinnerFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.TimeQuantumFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.TimedUploadParamFragment;
import com.cypher.encryptionanddecryption.fragment.protocol.nb25.VendorCustomMeterStatesFragment;
import com.cypher.encryptionanddecryption.util.HexUtils;
import com.cypher.encryptionanddecryption.util.KunLunProtocolUtils;
import com.cypher.encryptionanddecryption.util.Nb25ProtocolUtils;

import org.apache.commons.lang3.StringUtils;

import java.util.Date;
import java.util.HashMap;

public class BluetoothCommunicationActivity extends AppCompatActivity {
    /** AES 密钥 */
    private String KEY = "680025000C00842009705516";
    /** 随机码 */
    private String HASH_RANDOM = "680025000C0084000C261616";
    private Intent intent;
    private Button returnBtn;
    private Button readBtn;
    private Button writeBtn;
    private TextView tabTitle;
    private BluetoothGattManager gattManager;
    private CommunicationBean bean;
    private AbstractProtocolFragment protocolFragment;
    private Handler handler;
    public Handler getHandler() {
        return handler;
    }
    boolean isAesKey = false;
    private String aesKey;
    // 2.5协议需要获取秘钥
    public String getAesKey() {
        return aesKey;
    }
    /** 协议ID */
    private int protocolId;
    /**
     * 获取协议ID
     * @return
     */
    public int getProtocolId() {
        return protocolId;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bluetooth_communication);

        ApplicationManager.getInstance().getActivities().add(this);

        handler = new Handler();

        intent = getIntent();
        // 获取需要操作的对象
        bean = JSONObject.parseObject(intent.getStringExtra("bean"), CommunicationBean.class);
        protocolId = intent.getIntExtra("protocolId", 0);
        if (protocolId == 2) {
            KEY = "680000000C00942009333616";
            HASH_RANDOM = "680000000C0084000C261616";
        }
        tabTitle = findViewById(R.id.comm_top_title);
        tabTitle.setText(bean.getName());
        initBtn();

        initFragment(bean);

        // 获取蓝牙连接管理类
        gattManager = BluetoothManagerSingleton.getInstance().getBluetoothGattManager();

    }

    /**
     * 初始化按钮
     */
    private void initBtn() {
        // 返回上一步，关闭当前activity
        returnBtn = findViewById(R.id.comm_top_return);
        View.OnClickListener returnBtnClick = (v) -> {
            this.finish();
        };
        returnBtn.setOnClickListener(returnBtnClick);

        ProgressDialog waitingDialog =
                new ProgressDialog(this, R.style.AlertDialog);
        // 读数据按钮点击事件
        readBtn = findViewById(R.id.comm_read_send);
        View.OnClickListener readBtnClick = (v) -> {
            onclickHandler(waitingDialog, readBtn, "read", "正在读取，请稍后...",
                    R.drawable.shape_corner_cyan, R.drawable.button_select_blue,
                    "正在读取...");
        };
        readBtn.setOnClickListener(readBtnClick);

        // 写数据按钮点击事件
        writeBtn = findViewById(R.id.comm_write_send);
        View.OnClickListener writeBtnClick = (v) -> {
            onclickHandler(waitingDialog, writeBtn, "write", "正在写入，请稍后...",
                    R.drawable.shape_corner_green_yellow, R.drawable.button_select_yellow,
                    "正在写入...");
        };
        writeBtn.setOnClickListener(writeBtnClick);
    }

    /**
     * 按钮点击事件
     * @param waitingDialog
     *      等待框
     * @param btn
     *      操作按钮
     * @param rwType
     *      读写类型
     * @param tip
     *      等待框提示文字
     * @param startDrawableId
     *      按钮点击后的背景颜色
     * @param endDrawableId
     *      操作完成后的按钮北京颜色
     * @param btnText
     *      按钮点击后的文字
     */
    private void onclickHandler(ProgressDialog waitingDialog, Button btn, String rwType,
                                String tip, int startDrawableId, int endDrawableId, String btnText) {
        // 恢复按钮文字
        String text = btn.getText().toString();
        waitingDialog.setMessage(tip);
        waitingDialog.show();
        btn.setText(btnText);
        btn.setEnabled(false);
        btn.setBackground(ContextCompat.getDrawable(btn.getContext(), startDrawableId));
        // 蓝牙读取耗时间长，需要在子线程中处理
        new Thread(() -> {
            handler.post(() -> {
                sendData(rwType);
                waitingDialog.dismiss();
                btn.setText(text);
                btn.setEnabled(true);
                btn.setBackground(ContextCompat.getDrawable(btn.getContext(), endDrawableId));
            });
        }).start();
    }
    /**
     * 初始化Fragment
     * @param bean
     */
    private void initFragment(CommunicationBean bean) {
        // 特殊读取命令需要获取 AES key 值
        if (bean.getAttr() != null && bean.getAttr().containsKey("key")) {
            isAesKey = bean.getAttr().get("key") == null ? false : (boolean) bean.getAttr().get("key");
        }
        switch (bean.getRwType()) {
            case READONLY:
                switch (bean.getProtocolId()) {
                    case JIN_RAN:
                    case TOW_POINT_FIVE:
                        // 添加只读界面
                        // 处理特殊情况
                        if (StringUtils.equals("true", bean.getSpecial())) {
                            protocolFragment = new TimeQuantumFragment(this, bean);
                            break;
                        }
                        protocolFragment = new com.cypher.encryptionanddecryption.fragment
                                .protocol.nb25.ReadonlyFragment(bean);
                        break;
                    case KUN_LUN:
                        switch (bean.getHexCode()) {
                            case "803E000005EF08":
                                protocolFragment = new KunLunTimeQuantumFragment(this, bean);
                                break;
                            default:
                                // 添加只读界面
                                protocolFragment = new ReadonlyFragment(this.getApplicationContext(), bean);
                        }
                        break;
                }
                setWriteBtnStatus(bean.getRwType());
                break;
            case READ_WRITE:
                // 这块需要对每个页面进行单独处理
                setWriteBtnStatus(bean.getRwType());
                switch (bean.getProtocolId()) {
                    case TOW_POINT_FIVE:
                        initTwoPointFiveWriteFragment(bean);
                        break;
                    case KUN_LUN:
                        // 添加只读界面
                        initKunLunWriteFragment(bean);
                        break;
                }
                break;
        }
        if (protocolFragment != null) showFragment();
    }

    /**
     * 初始化昆仑读写页面
     * @param bean
     */
    private void initKunLunWriteFragment(CommunicationBean bean) {
        switch (bean.getHexCode()) {
            case "030110FF": // 读写错误代码
                protocolFragment = new ErrCodeFragment(this, bean);
                // 读写错误代码需要先禁用写数据按钮
                setWriteBtnStatus(CommunicationBean.RWType.READONLY);
                break;
            case "00B0830008": // 读写表号
                protocolFragment = new MeterNumberFragment(this, bean);
                break;
            case "00B0840049": // 写参数
                protocolFragment = new ParamFragment(this, bean);
                break;
            case "030110FF,030110FE": // 写状态/温补参数
                setReadBtnStatus(CommunicationBean.RWType.READONLY);
                protocolFragment = new WriteStateFragment(this, bean);
                break;
            case "00B0911C01": // 写参数
                protocolFragment = new FlowCoefficientFragment(this, bean);
                break;
        }
    }

    /**
     * 初始化2.5读写页面
     * @param bean
     */
    private void initTwoPointFiveWriteFragment(CommunicationBean bean) {
        switch (bean.getHexCode()) {
            case "0002":
                protocolFragment = new ClockFragment(this, bean);
                break;
            case "000B":
                protocolFragment = new MeterStateFragment(this, bean);
                break;
            case "0100":
                protocolFragment = new VendorCustomMeterStatesFragment(this, bean);
                break;
            case "2006":
                protocolFragment = new TimedUploadParamFragment(this, bean);
                break;
            case "2007":
                protocolFragment = new CollectionServiceParamFragment(this, bean);
                break;
            case "2009":
                protocolFragment = new SecretKeyParamFragment(this, bean);
                break;
            case "2023":
            case "2202":
                protocolFragment = new AbnormallyHighFlowParamsFragment(this, bean);
                break;
            default:
                if (StringUtils.equals("edit", bean.getInputType())) {
                    protocolFragment = new SimpleEditFragment(this, bean);
                } else if (StringUtils.equals("spinner", bean.getInputType())) {
                    // 通讯模式禁用写入按钮
                    if (StringUtils.equals("2005", bean.getHexCode())) {
                        // 读写错误代码需要先禁用写数据按钮
                        setWriteBtnStatus(CommunicationBean.RWType.READONLY);
                    }
                    protocolFragment = new SimpleSpinnerFragment(this, bean);
                }
        }
    }

    /**
     * 设置写数据按钮禁用状态
     * @param type
     */
    public void setWriteBtnStatus(CommunicationBean.RWType type) {
        switch (type) {
            case READONLY:
                writeBtn.setEnabled(false);
                writeBtn.setBackground(ContextCompat.getDrawable(this, R.drawable.button_select_light_slate_gray));
                break;
            case READ_WRITE:
                writeBtn.setEnabled(true);
                writeBtn.setBackground(ContextCompat.getDrawable(this, R.drawable.button_select_yellow));
                break;
        }
    }
    /**
     * 设置读数据按钮禁用状态
     * @param type
     */
    public void setReadBtnStatus(CommunicationBean.RWType type) {
        switch (type) {
            case READONLY:
                readBtn.setEnabled(false);
                readBtn.setBackground(ContextCompat.getDrawable(this, R.drawable.button_select_light_slate_gray));
                break;
            case READ_WRITE:
                readBtn.setEnabled(true);
                readBtn.setBackground(ContextCompat.getDrawable(this, R.drawable.button_select_blue));
                break;
        }
    }
    /**
     * 向蓝牙发送数据
     */
    private void sendData(String rwType) {
        if (protocolFragment == null) {
            Toast.makeText(this, bean.getName() + "功能未开发", Toast.LENGTH_SHORT)
                    .show();
            return;
        }

        // 每次在发起命令的时候都需要设置接收状态为false
        // 以防其他设备向下位机发送信息，
        // 下位机回传命令到蓝牙
        gattManager.setReceiveData(false);

        // 提示文字
        String failTip = "读取失败";
        if (StringUtils.equals("write", rwType))  {
            failTip = "写入失败";
        }

        // 根据协议类型特殊情况处理失败，则不向下执行
        if (!specialHandling(rwType)) {
            return;
        }
        // 特殊情况处理，如果不是特殊情况则返回true
        if (!protocolFragment.specialCases(gattManager, rwType)) {
            return;
        }
        // 获取发送命令
        String command = protocolFragment.getHexCode(rwType);
        // 如果发送命令为空，则不执行后续代码
        if (StringUtils.isEmpty(command)) {
            return;
        }
        // 发送命令到设备
        gattManager.sendMsg(HexUtils.hexToBytes(command));
        // 发送码加入对话列表中
        gattManager.addList("<- " + HexUtils.formatHex(command));

        if (checkData(bean.getName() + failTip)) {
            // 校验成功设置校验结果为false
            gattManager.setReceiveData(false);
            // 读取的时候需要渲染页面
            if (StringUtils.equals("read", rwType)) {
                protocolFragment.fillFragment(HexUtils.bytesToHex(gattManager.getBuf()));
            } else {
                // 校验数据是否写入成功
                String writeState = "写入成功";
                if (!protocolFragment.checkData(
                        HexUtils.bytesToHex(gattManager.getBuf()),
                        bean.getProtocolId().ordinal())) {
                    writeState = "写入失败";
                }
                Toast.makeText(this, writeState, Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * 校验数据是否合法
     * @return
     */
    public boolean checkData(String tip) {
        // 数据校验
        if (gattManager.isReceiveData()) return true;
        // 如果一秒内还为校验成功，则为超时
        long time = new Date().getTime();
        while(true) {
            // 校验成功
            if (gattManager.isReceiveData()) return true;

            long runTime = new Date().getTime();
            // 超时
            if (runTime - time >= 10000) {
                // 设置未接收完未否，蓝牙接收失败
                gattManager.setNotReceived(false);
                Toast.makeText(this, tip, Toast.LENGTH_SHORT).show();
                return false;
            }
        }
    }

    /**
     * 展示昆仑页面
     */
    private void showFragment() {
        if (!protocolFragment.isAdded()) {
            getSupportFragmentManager().beginTransaction().add(R.id.result_fragment, protocolFragment).commitAllowingStateLoss();
        }
        getSupportFragmentManager().beginTransaction().show(protocolFragment).commitAllowingStateLoss();
    }

    /**
     * 根据发送码从硬件获取数据
     * @param data
     */
    private void getCommand(String data) {
        // 发送命令到设备
        gattManager.sendMsg(HexUtils.hexToBytes(data));
        // 发送码加入对话列表中
        gattManager.addList("<- " + HexUtils.formatHex(data));
    }

    /**
     * 根据协议类型处理特殊情况
     */
    private boolean specialHandling(String rwType) {
        switch (protocolId) {
            case 1:
                // 激活红外
                KunLunProtocolUtils.wakeUpInfrared(gattManager);
                // 如果激活红外失败，则程序不往下执行
                if (!checkData("激活红外通信失败")) {
                    return false;
                }
                break;
            case 0:
            case 2:
                if (isAesKey || StringUtils.equals("write", rwType)) {
                    if (StringUtils.isEmpty(aesKey)) {
                        // 获取密钥
                        getCommand(KEY);
                        // 如果激活红外失败，则程序不往下执行
                        if (!checkData("获取密钥失败")) {
                            return false;
                        }
                        // 密钥是32个字节
                        aesKey = Nb25ProtocolUtils.formatReceiveData
                                (HexUtils.bytesToHex(gattManager.getBuf())).substring(4, 36);
                        Nb25ProtocolUtils.key = aesKey;
                        // 校验成功设置校验结果为false
                        gattManager.setReceiveData(false);
                    }
                    if (StringUtils.equals("write", rwType)) {
                        // 获取随机码
                        getCommand(HASH_RANDOM);
                        // 如果激活红外失败，则程序不往下执行
                        if (!checkData("获取随机码失败")) {
                            return false;
                        }
                        // 随机码是32个字节
                        Nb25ProtocolUtils.random = Nb25ProtocolUtils.formatReceiveData
                                (HexUtils.bytesToHex(gattManager.getBuf())).substring(0, 32);
                    }
                    break;
                }
        }
        // 校验成功设置校验结果为false
        gattManager.setReceiveData(false);
        return true;
    }
}